package com.sogou.qadev.service.login.client;

import java.io.IOException;
import java.util.HashSet;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.sogou.qadev.service.login.bean.DataAndEventId;
import com.sogou.qadev.service.login.bean.Key;
import com.sogou.qadev.service.login.client.authenticate.AuthenticateProxy;
import com.sogou.qadev.service.login.client.randomkey.RandomKeyProxy;

public class LoginFilter implements Filter
{
	static public final int CAN_SKIP_INPUT = 1;

	static public final int CAN_NOT_SKIP_INPUT = 2;

	private int retryAccount = 5;

	private long productId = -1;

	private DataAndEventId[] dataAndEventId = null;

	private String sendRedirectUrl = null;
	
	private String sendErrorRedirectUrl = null;

	private String magic = null;

	private HashSet<String> magicUrlSet = new HashSet<String>();

	private HashSet<String> noIEUrlSet = new HashSet<String>();

	private RandomKeyProxy randomKeyProxy = new RandomKeyProxy();

	private AuthenticateProxy authenticateProxy = new AuthenticateProxy();

	public void destroy()
	{
	}

	public void init(FilterConfig config) throws ServletException
	{
		magic = trimSafe(config.getInitParameter("magic"));
		sendRedirectUrl = trimSafe(config.getInitParameter("sendRedirectUrl"));
		sendErrorRedirectUrl = trimSafe(config.getInitParameter("sendErrorRedirectUrl"));

		String pid = trimSafe(config.getInitParameter("productId"));
		String retry = trimSafe(config.getInitParameter("retryAccount"));

		String idString = trimSafe(config.getInitParameter("dataAndEventIds"));
		String magicUrls = trimSafe(config.getInitParameter("magicUrls"));
		String noIEUrls = trimSafe(config.getInitParameter("noIEUrls"));

		if (valid(pid))
			productId = Long.parseLong(pid);

		if (valid(retry))
			retryAccount = Integer.parseInt(retry);

		if (valid(idString))
		{
			String[] pairString = idString.split(";");

			dataAndEventId = new DataAndEventId[pairString.length];
			for (int i = 0; i < pairString.length; i++)
			{
				String dataId = pairString[i].split(",")[0];
				String eventId = pairString[i].split(",")[1];

				dataAndEventId[i] = new DataAndEventId();

				if (!"".equals(dataId.trim()))
					dataAndEventId[i].setDataId(Long.parseLong(dataId));

				if (!"".equals(eventId.trim()))
					dataAndEventId[i].setEventId(Long.parseLong(eventId));
			}
		}

		if (valid(magicUrls))
		{
			String[] urls = magicUrls.split(";");
			for (String url : urls)
				if (valid(url))
					magicUrlSet.add(url);
		}
		
		System.err.println("magic url set is: " + magicUrlSet);

		if (valid(noIEUrls))
		{
			String[] urls = noIEUrls.split(";");
			for (String url : urls)
				if (valid(url))
					noIEUrlSet.add(url);
		}
		
		System.err.println("no ie url set is: " + noIEUrlSet);
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain nextFilter) throws IOException, ServletException
	{
		long start = System.currentTimeMillis();

		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpSession session = httpRequest.getSession();
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		// ����Ƿ�Ҫ�����Ҫ�Ƕ�ʱ���ץȡ
		String source = httpRequest.getServletPath();
		if (source.indexOf("/") >= 0)
			source = source.substring(source.lastIndexOf("/") + 1);

		if (magicUrlSet.contains(source))
		{
			if (magic != null && magic.equals(request.getParameter("magic")))
			{
				nextFilter.doFilter(request, response);
				return;
			}
		}

		Key key = (Key) session.getAttribute("key");
		long k = -1;

		if (session.getAttribute("kid") != null)
			k = (Long) session.getAttribute("kid");
		
		if (k <= 0)
		{
			session.removeAttribute("kid");
			k = -1;
		}

		if (k <= 0 || key == null)
		{
			String redirectUrl = null;

			if (!valid(sendRedirectUrl))
				redirectUrl = httpRequest.getRequestURL() + (httpRequest.getQueryString() == null ? "" : ("?" + httpRequest.getQueryString()));
			else
				redirectUrl = sendRedirectUrl;

			String kid = null;
			if (k <= 0)
			{
				kid = request.getParameter("k");
				if (kid != null)
				{
					try
					{
						k = Long.parseLong(kid);
					}
					catch(Exception e)
					{
					}
				}
				
				if (k > 0)
					session.setAttribute("kid", k);
			}
			else
			{
				kid = Long.toString(k);
			}

			if (k > 0 && key == null)
			{
				key = randomKeyProxy.getKey(k);
				if (key != null)
				{
					session.setAttribute("key", key);
				}
				else
				{
					k = -1;
					kid = null;
				}
			}

			if (kid == null || key == null)
			{
				String url = randomKeyProxy.getKeyId(productId, dataAndEventId, redirectUrl, null, retryAccount, null);

				kid = getKeyId(url);
				k = Long.parseLong(kid);

				session.setAttribute("kid", k);

				if (noIEUrlSet.contains(source))
				{
					if (url.indexOf("/?") > 0)
						//url = url.replaceAll("/\\?", "/index.noie.jsp\\?");
						url = url.replaceAll("/\\?", "/index.jsp\\?");
					else if (url.indexOf("/index.jsp?") > 0)
						//url = url.replaceAll("/index.jsp\\?", "/index.noie.jsp\\?");
						url = url.replaceAll("/index.jsp\\?", "/index.jsp\\?");
				}

				httpResponse.sendRedirect(url);
				return;
			}
		}

		// ���key�Ϸ���
		String url = checkKey(key, httpResponse, session, k);
		if (url != null)
		{
			httpResponse.sendRedirect(url);
			return;
		}

		if (nextFilter != null)
			nextFilter.doFilter(request, response);

		System.out.println("login filter time: " + (System.currentTimeMillis() - start));
	}

	protected String checkKey(Key key, HttpServletResponse httpResponse, HttpSession session, long kid) throws IOException
	{
		if (key.getUsername() == null || key.getUserID() <= 0)
		{
			session.removeAttribute("key");
			System.err.println("here is a key, but username/userid is invalid, username is: " + key.getUsername() + ", user id is: " + key.getUserID());
			return getLoginUrl(key.getLoginUrlPrefix(), kid, CAN_SKIP_INPUT);
		}

		if (this.productId <= 0)
			return null;

		int[] result = authenticateProxy.authenticate0(kid, productId, dataAndEventId);
		if (result == null)
			return sendErrorRedirectUrl;

		if (result.length == 0)
			return null;

		for (int r : result)
			if (r <= 0)
				return sendErrorRedirectUrl;

		return null;
	}

	protected String trimSafe(String str)
	{
		if (str == null)
			return null;

		return str.trim();
	}

	protected boolean valid(String str)
	{
		return str != null && str.length() > 0;
	}

	protected String getKeyId(String url)
	{
		try
		{
			String[] kvs = url.split("\\?")[1].split("&");
			for (String kv : kvs)
			{
				String[] s = kv.split("=");
				if ("k".equals(s[0]))
					return s[1];
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}

		return null;
	}

	protected String getLoginUrl(String loginUrlPrefix, long keyID, int e)
	{
		return loginUrlPrefix != null ? loginUrlPrefix + "e=" + e + "&k=" + keyID : "https://login.sogou-inc.com/?e=" + e + "&k=" + keyID;
	}
}
